// ValidationAspects
// Written by Mike Saunders
// Released under Microsoft Public License (Ms-PL)
using System;
using System.Collections.Generic;
using System.Reflection;
using NUnit.Framework;
using ValidationAspects;
using ValidationAspects.Configuration;
using ValidationAspects.Sdk;

namespace TestValidationAspects.Configuration
{
	[TestFixture]
	public class TestParameterValidation
	{
		[SetUp]
		public void SetUp()
		{
			TestHelpers.ResetFramework();
		}

		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_Registry_throws_for_null_param()
		{
			new ParameterValidation().Register(null);
		}

		[Test]
		public void Test_default_get_Apply()
		{
			Assert.AreEqual(ValidationApplication.Add, new ParameterValidation().Apply);
		}

		[Test]
		public void Test_Register_throws_if_property_is_unknown()
		{
			MethodInfo methodInfo = typeof(Dummy).GetMethod("Method");
			Test.Throws<ValidationConfigurationException>(() => new ParameterValidation {Parameter = "unknown"}.Register(methodInfo),
			                                              string.Format("Parameter [name:{0}] [method:{1}] [type:{2}] is unknown.", "unknown", methodInfo, methodInfo.DeclaringType));
		}

		[Test]
		public void Test_Register_with_Apply_Add_adds_factories()
		{
			MockValidatorFactory<string> factoryA = new MockValidatorFactory<string>();
			Assert.IsNull(factoryA.Value);

			MethodInfo methodInfo = typeof(Dummy).GetMethod("Method");

			ParameterInfo parameterInfo = methodInfo.GetParameters()[0];
			parameterInfo.ReplaceValidation(new[] {factoryA});

			MockValidatorFactory<string> factoryB = new MockValidatorFactory<string>();
			Assert.IsNull(factoryB.Value);

			ParameterValidation parameterValidation = new ParameterValidation {Apply = ValidationApplication.Add, Parameter = "paramA", Validators = new List<IValidatorFactory> {factoryB}};
			parameterValidation.Register(methodInfo);

			IValidationContext context = new MockValidationContext();
			const string value = "text";
			parameterInfo.ResolveValidator().Invoke(value, context);

			factoryA.TestState(value, context);
			factoryB.TestState(value, context);
		}

		[Test]
		public void Test_Register_with_Apply_Replace_replaces_factories()
		{
			MockValidatorFactory<string> factoryA = new MockValidatorFactory<string>();
			Assert.IsNull(factoryA.Value);

			MethodInfo methodInfo = typeof(Dummy).GetMethod("Method");

			ParameterInfo parameterInfo = methodInfo.GetParameters()[0];
			parameterInfo.ReplaceValidation(new[] {factoryA});

			MockValidatorFactory<string> factoryB = new MockValidatorFactory<string>();
			Assert.IsNull(factoryB.Value);

			ParameterValidation parameterValidation = new ParameterValidation {Apply = ValidationApplication.Replace, Parameter = "paramA", Validators = new List<IValidatorFactory> {factoryB}};
			parameterValidation.Register(methodInfo);

			IValidationContext context = new MockValidationContext();
			const string value = "text";
			parameterInfo.ResolveValidator().Invoke(value, context);

			factoryA.TestState(null, null);
			factoryB.TestState(value, context);
		}

		#region Mocks
		public class Dummy
		{
			public void Method(string paramA, string paramB) {}
		}
		#endregion
	}
}